package com.bolt.support.codegenerator.util;

import com.bolt.common.io.FileUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.convention.exception.ServiceException;
import com.bolt.support.codegenerator.dto.ColumnInfo;
import com.bolt.support.codegenerator.dto.ConfigInfo;
import com.bolt.support.codegenerator.model.Column;
import com.bolt.support.codegenerator.model.Table;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class GeneratorUtil {

    private static List<String> templateNames = new ArrayList<>();

    private static final String TIMESTAMP = "Timestamp";

    private static final String BIGDECIMAL = "BigDecimal";

    public static final String EXTRA = "auto_increment";

    static {
        templateNames.add("Dto");
        templateNames.add("Controller");
        templateNames.add("Converter");
        templateNames.add("Entity");
        templateNames.add("Repository");
        templateNames.add("Service");
        templateNames.add("QueryCriteria");

        templateNames.add("api");
        templateNames.add("index");

    }

    private static Configuration getConfiguration() {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_25);
        // 设置FreeMarker的模版文件位置
        cfg.setClassForTemplateLoading(GeneratorUtil.class, "/code_templates");
        cfg.setNumberFormat("###############");
        cfg.setBooleanFormat("true,false");
        cfg.setDefaultEncoding("UTF-8");
        return cfg;
    }

    public static List<Map<String, Object>> generatorCode(Table table, ConfigInfo genConfig) {
        try {
            Map<String, Object> genMap = getGenMap(table, genConfig);
            List<Map<String, Object>> genList = new ArrayList<>();
            Configuration cfg = getConfiguration();
            for (String templateName : templateNames) {
                StringWriter output = new StringWriter();
                Map<String, Object> map = new HashMap<>(1);
                Template template = cfg.getTemplate(templateName + ".ftl");
                template.process(genMap, output);
                map.put("content", output.toString());
                map.put("name", templateName);
                genList.add(map);
            }
            return genList;
        } catch (Exception ex) {
            throw new ServiceException(ex);
        }
    }

    public static void generatorCode(String templateName, Table table, Configuration configuration, ConfigInfo genConfig) {
        try {
            Map<String, Object> genMap = getGenMap(table, genConfig);
            Configuration cfg = configuration == null ? getConfiguration() : configuration;
            StringWriter output = new StringWriter();
            Template template = cfg.getTemplate(templateName + ".ftl");
            template.process(genMap, output);
            String filePath = GeneratorUtil.getFilePath(templateName, genConfig.getPack(), table.getClassName(genConfig.isFullTableName()), genConfig.getPath());
            FileUtil.writeUtf8String(output.toString(), filePath);
        } catch (Exception ex) {
            throw new ServiceException(ex);
        }
    }


    private static Column findColumn(Table table, String sqlName) {
        List<Column> columns = table.getColumns();
        Column col = null;
        for (Column column : columns) {
            if (column.getSqlName().equals(sqlName)) {
                col = column;
            }
        }
        return col;
    }

    // 获取模版数据
    private static Map<String, Object> getGenMap(Table table, ConfigInfo genConfig) {
        table.initClassName(genConfig.isFullTableName());
        // 存储模版字段数据
        Map<String, Object> genMap = new HashMap<>(16);
        // 包名称
        genMap.put("package", genConfig.getPack());
        genMap.put("table", table);
        String pack = genConfig.getPack();
        String moduleName = StrUtil.subAfter(pack, ".", true);
        genMap.put("mappingUrl", moduleName + "/" + StrUtil.lowerFirst(table.getClassName(genConfig.isFullTableName())));
        genMap.put("moduleName", moduleName);

        genMap.put("componentName", StrUtil.lowerFirst(table.getClassName(genConfig.isFullTableName())));

        genMap.put("className", table.getClassName(genConfig.isFullTableName()));
        genMap.put("apiAlias", table.getRemarks());
        genMap.put("hasQuery", false);
        genMap.put("hasDict", false);
        genMap.put("queryHasTimestamp", false);
        genMap.put("queryHasBigDecimal", false);
        if (table.getPkColumn() != null) {
            genMap.put("pkColName", table.getPkColumn().getJavaProperty());
        }

        // 保存字段信息
        List<Map<String, Object>> columns = new ArrayList<>();
        // 保存查询字段的信息
        List<Map<String, Object>> queryColumns = new ArrayList<>();
        // 存储字典信息
        List<String> dicts = new ArrayList<>();
        // 存储 between 信息
        List<Map<String, Object>> betweens = new ArrayList<>();
        // 存储不为空的字段信息
        List<Map<String, Object>> isNotNullColumns = new ArrayList<>();

        for (ColumnInfo column : genConfig.getColumnInfos()) {
            Map<String, Object> listMap = new HashMap<>(16);
            // 字段描述
            listMap.put("remark", column.getRemarks());
            // 字段类型
            String colType = table.getColumn(column.getSqlName()).getJavaType();
            // 是否存在 Timestamp 类型的字段
            if (TIMESTAMP.equals(colType)) {
                genMap.put("hasTimestamp", true);
            }
            // 是否存在 BigDecimal 类型的字段
            if (BIGDECIMAL.equals(colType)) {
                genMap.put("hasBigDecimal", true);
            }

            // 主键存在字典
            if (StrUtil.isNotBlank(column.getDictName())) {
                genMap.put("hasDict", true);
                dicts.add(column.getDictName());
            }

            listMap.put("moduleName", moduleName);

            // 小写开头的字段名称
            listMap.put("columnName", StrUtil.toCamelCase(column.getSqlName()));
            // 存储字原始段名称
            listMap.put("columnSqlName", column.getSqlName());

            // 不为空
            listMap.put("istNotNull", column.getNotNull());
            // 字段列表显示
            listMap.put("columnShow", column.getListShow());
            // 表单显示
            listMap.put("formShow", column.getFormShow());
            // 表单组件类型
            listMap.put("formType", StrUtil.isNotBlank(column.getFormType()) ? column.getFormType() : "Input");


            Column dbColumn = findColumn(table, column.getSqlName());
            listMap.put("javaClass", dbColumn.getJavaType());
            listMap.put("javaProperty", dbColumn.getJavaProperty());
            // 字典名称
            listMap.put("dictName", column.getDictName());
            // 日期注解
            listMap.put("dateAnnotation", column.getDateAnnotation());
            if (StrUtil.isNotBlank(column.getDateAnnotation())) {
                genMap.put("hasDateAnnotation", true);
            }
            // 添加非空字段信息
            if (column.getNotNull()) {
                isNotNullColumns.add(listMap);
            }
            // 判断是否有查询，如有则把查询的字段set进columnQuery
            if (!StrUtil.isBlank(column.getQueryType())) {
                // 查询类型
                listMap.put("queryType", column.getQueryType());
                // 是否存在查询
                genMap.put("hasQuery", true);
                if (TIMESTAMP.equals(colType)) {
                    // 查询中存储 Timestamp 类型
                    genMap.put("queryHasTimestamp", true);
                }
                if (BIGDECIMAL.equals(colType)) {
                    // 查询中存储 BigDecimal 类型
                    genMap.put("queryHasBigDecimal", true);
                }
                if ("between".equalsIgnoreCase(column.getQueryType())) {
                    betweens.add(listMap);
                } else {
                    // 添加到查询列表中
                    queryColumns.add(listMap);
                }
            }
            // 添加到字段列表中
            columns.add(listMap);
        }
        // 保存字段列表
        genMap.put("columns", columns);
        // 保存查询列表
        genMap.put("queryColumns", queryColumns);
        // 保存字段列表
        genMap.put("dicts", dicts);
        // 保存查询列表
        genMap.put("betweens", betweens);
        // 保存非空字段信息
        genMap.put("isNotNullColumns", isNotNullColumns);
        return genMap;
    }

    public static String getFilePath(String templateName, String basePackage, String className, String rootPath) {

        String packagePath = rootPath + File.separator + basePackage.replace(".", File.separator) + File.separator;
        if ("Entity".equals(templateName)) {
            return packagePath + "entity" + File.separator + className + "Entity.java";
        }

        if ("Controller".equals(templateName)) {
            return packagePath + "controller" + File.separator + className + "Controller.java";
        }

        if ("Service".equals(templateName)) {
            return packagePath + "service" + File.separator + className + "Service.java";
        }

        if ("Dto".equals(templateName)) {
            return packagePath + "dto" + File.separator + className + "DTO.java";
        }

        if ("Repository".equals(templateName)) {
            return packagePath + "repository" + File.separator + className + "Repository.java";
        }

        if ("Converter".equals(templateName)) {
            return packagePath + "dto" + File.separator + "converter" + File.separator + className + "Converter.java";
        }

        if ("QueryCriteria".equals(templateName)) {
            return packagePath + "dto" + File.separator + className + "QueryCriteria.java";
        }

        if ("api".equals(templateName)) {
            return packagePath + "view" + File.separator + className + ".js";
        }
        if ("index".equals(templateName)) {
            return packagePath + "view" + File.separator + "index.vue";
        }


        if ("EntityBO".equals(templateName)) {
            return packagePath + "bo" + File.separator + className + "BO.java";
        }
        if ("EntityDO".equals(templateName)) {
            return packagePath + "model" + File.separator + className + "DO.java";
        }

        if ("Manager".equals(templateName)) {
            return packagePath + "manager" + File.separator + className + "Manager.java";
        }

        if ("ManagerImpl".equals(templateName)) {
            return packagePath + "manager" + File.separator + "impl" + File.separator + className + "ManagerImpl.java";
        }

        if ("Mapper.java".equals(templateName)) {
            return packagePath + "mapper" + File.separator + className + "Mapper.java";
        }
        if ("Mapper.xml".equals(templateName)) {
            return packagePath + "mapper" + File.separator +  className + "Mapper.xml";
        }
        return null;
    }

}


 